package com.scau402.system1.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scau402.common.constant.DeptConstants;
import com.scau402.common.constant.InboundConstants;
import com.scau402.common.constant.JadeConstants;
import com.scau402.common.core.domain.AjaxResult;
import com.scau402.common.core.domain.entity.SysUser;
import com.scau402.common.enums.outbound.OutboundType;
import com.scau402.common.exception.ServiceException;
import com.scau402.common.utils.DateUtils;
import com.scau402.common.utils.SecurityUtils;
import com.scau402.common.utils.code.InboundOrderCodeUtils;
import com.scau402.system.constants.SystemConstants;
import com.scau402.system.domain.WmsBasicClient;
import com.scau402.system.domain.WmsBasicProcessor;
import com.scau402.system.domain.WmsBasicSupplier;
import com.scau402.system.domain.WmsInboundOrder;
import com.scau402.system.mapper.WmsBasicProcessorMapper;
import com.scau402.system.mapper.WmsOutboundOrderMapper;
import com.scau402.system.service.ISysTenantService;
import com.scau402.system.service.IWmsJadeService;
import com.scau402.system1.domain.bo.*;
import com.scau402.system1.domain.dto.InboundDTO;
import com.scau402.system1.domain.po.*;
import com.scau402.system1.domain.query.InboundJadeQuery;
import com.scau402.system1.domain.query.WmsInboundOrderQuery;
import com.scau402.system1.domain.vo.WmsInboundJadeVO;
import com.scau402.system1.domain.vo.WmsInboundOrderVO;
import com.scau402.system1.mapper.*;
import com.scau402.system1.repository.IWmsInboundOrderRepository;
import com.scau402.system1.repository.IWmsJadeRepository;
import com.scau402.system1.repository.IWmsWarehouseRepository;
import com.scau402.system1.service.IWmsInboundOrderService;
import com.scau402.system1.service.assembler.WmsInboundVOAssembler;
import com.scau402.system1.utils.IdGenerator;
import com.scau402.constants.RedisConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.scau402.constants.RedisConstants.DUP_KEY;
import static com.scau402.constants.RedisConstants.INBOUND_PREFIX;

/**
 * <p>
 * 商品入库单主表 服务实现类
 * </p>
 *
 * @author
 * @since 2023-12-23
 */
@Service
@Slf4j

public class IWmsInboundOrderServiceImpl implements IWmsInboundOrderService {
    @Autowired
    private IWmsOutboundOrderMapper wmsOutboundOrderMapper;

    @Autowired
    private IWmsInboundOrderMapper wmsInboundOrderMapper;

    @Autowired
    private IWmsInboundOrderDetailMapper wmsInboundOrderDetailMapper;

    @Autowired
    private IWmsJadeService jadeService;

    @Autowired
    private ISysTenantService tenantService;

    @Autowired
    private IWmsInboundOrderRepository wmsInboundOrderRepository;

    @Autowired
    private IWmsJadeRepository wmsJadeRepository;

    @Autowired
    private IWmsWarehouseRepository wmsWarehouseRepository;

    // TODO  2024/1/3 16:54: 后续不要使用mapper，使用repository
    @Autowired
    private WmsJadeMapperV2 wmsJadeMapper;

    @Autowired
    private WmsBasicSupplierMapperV2 wmsBasicSupplierMapper;

    @Autowired
    private WmsBasicClientMapperV2 wmsBasicClientMapper;

    @Autowired
    private WmsBasicProcessorMapper wmsBasicProcessorMapper;

    @Autowired
    private WmsInboundVOAssembler wmsInboundVOAssembler;
    @Autowired
    private IWmsAuditOrderServiceImpl auditOrderService;
    @Autowired
    private IdGenerator idGenerator;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;



    public List<WmsInboundOrderVO> selectWmsInboundOrderList(WmsInboundOrderQuery query) {
        // 返回入库单、入库单明细、玉石信息、供应商、客户、仓库、仓位
        if (Objects.isNull(query.getTenantId())) {
            query.setTenantId(SecurityUtils.getTenantId());
        }
        log.info("查询入库单列表，参数：{}", query);

        // 获取入库单和入库单明细
        List<WmsInboundOrderBO> inboundOrderBOList = wmsInboundOrderRepository.getByCondition(query);
        List<String> inboundOrderCodeList = inboundOrderBOList.stream().map(WmsInboundOrderBO::getOrderCode).collect(Collectors.toList());
        Map<String, WmsInboundOrderBO> inboundOrderMap = inboundOrderBOList.stream()
                .collect(
                        Collectors.toMap(
                                WmsInboundOrderBO::getOrderCode,
                                Function.identity(),
                                (a, b) -> a)
                );

        // 获取翡翠信息
        // TODO  2024/1/6 23:17: 从入库单的明细的翡翠id查询
        List<Long> jadeIdList = inboundOrderBOList.stream()
                .flatMap(orderBO -> orderBO.getWmsInboundOrderDetailBOList().stream().map(WmsInboundOrderDetailBO::getJadeId))
                .collect(Collectors.toList());
        List<WmsJadeBO> jadeBOList = wmsJadeRepository.findByIds(jadeIdList, query.getTenantId());
        Map<Long, WmsJadeBO> jadeBOMap = jadeBOList.stream().collect(Collectors.toMap(WmsJadeBO::getId, Function.identity()));
        // 构造map<入库单号,翡翠BO>
        Map<String, List<WmsJadeBO>> inboundOrderCodeJadeBOMap = inboundOrderMap.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getWmsInboundOrderDetailBOList().stream()
                        .filter(Objects::nonNull)
                        .map(WmsInboundOrderDetailBO::getJadeId)
                        .filter(Objects::nonNull)
                        .map(jadeBOMap::get)
                        .collect(Collectors.toList())));

        // TODO  2024/1/3 17:05: 懒得改DDD了，先直接用PO对象，后续再改
        // 获取供应商信息
        // 获取inboundOrderBOList中的所有唯一供应商id
        List<Long> supplierIdList = inboundOrderBOList.stream().map(WmsInboundOrderBO::getSupplierId).distinct().collect(Collectors.toList());
        Map<Long, WmsBasicSupplier> supplierMap = CollectionUtils.isEmpty(supplierIdList) ? new HashMap<>(0) : Optional
                .ofNullable(wmsBasicSupplierMapper.selectList(Wrappers.<WmsBasicSupplier>lambdaQuery()
                        .eq(WmsBasicSupplier::getDelFlag, '0')
                        .eq(WmsBasicSupplier::getTenantId, query.getTenantId())
                        .in(WmsBasicSupplier::getId, supplierIdList)))
                .orElse(new ArrayList<>(0))
                .stream()
                .collect(Collectors.toMap(WmsBasicSupplier::getId, Function.identity()));

        // TODO  2024/1/3 17:05: 懒得改DDD了，先直接用PO对象，后续再改
        // 获取客户信息
        // 获取inboundOrderBOList中的所有唯一客户id
        List<Long> customerIdList = inboundOrderBOList.stream().map(WmsInboundOrderBO::getClientId).distinct().collect(Collectors.toList());
        Map<Long, WmsBasicClient> clientMap = Optional.ofNullable(wmsBasicClientMapper.selectList(Wrappers.<WmsBasicClient>lambdaQuery()
                        .eq(WmsBasicClient::getDelFlag, '0')
                        .eq(WmsBasicClient::getTenantId, query.getTenantId())
                        .in(WmsBasicClient::getId, customerIdList)))
                .orElse(new ArrayList<>(0))
                .stream()
                .collect(Collectors.toMap(WmsBasicClient::getId, Function.identity()));

        // TODO  2024/1/3 17:05: 懒得改DDD了，先直接用PO对象，后续再改
        // 获取加工厂信息
        // 获取inboundOrderBOList中的所有唯一加工厂id
        List<Long> processorIdList = inboundOrderBOList.stream().map(WmsInboundOrderBO::getProcessorId).distinct().collect(Collectors.toList());
        Map<Long, WmsBasicProcessor> processorMap = CollectionUtils.isEmpty(processorIdList) ? new HashMap<>(0) : Optional.ofNullable(wmsBasicProcessorMapper.selectList(Wrappers.<WmsBasicProcessor>lambdaQuery()
                        .eq(WmsBasicProcessor::getDelFlag, '0')
                        .eq(WmsBasicProcessor::getTenantId, query.getTenantId())
                        .in(WmsBasicProcessor::getId, processorIdList)))
                .orElse(new ArrayList<>(0))
                .stream()
                .collect(Collectors.toMap(WmsBasicProcessor::getId, Function.identity()));

        // 获取仓库信息
        // 获取inboundOrderBOList中的所有唯一仓库id
        List<Long> warehouseIdList = inboundOrderBOList.stream().map(WmsInboundOrderBO::getDesWarehouseId).distinct().collect(Collectors.toList());
        Map<Long, WmsWarehouseBO> warehouseBOMap = Optional.ofNullable(wmsWarehouseRepository.findByIds(warehouseIdList, query.getTenantId()))
                .orElse(new ArrayList<>(0))
                .stream()
                .collect(Collectors.toMap(WmsWarehouseBO::getId, Function.identity()));

        // 组装VO数据
        return wmsInboundVOAssembler.toInboundOrderVOList(inboundOrderBOList, inboundOrderCodeJadeBOMap, supplierMap, clientMap, processorMap, warehouseBOMap);
    }

    @Override
    public List<WmsInboundJadeVO> selectInboundJadeList(InboundJadeQuery query) {
        if (Objects.isNull(query.getTenantId())) {
            query.setTenantId(SecurityUtils.getTenantId());
        }
        log.info("查询入库单列表，参数：{}", query);

        List<WmsJadeBO> jadeBOList = wmsJadeRepository.getByCondition(query, true);
        log.info("查询入库单列表，翡翠信息数量：{}", jadeBOList.size());
        if (CollectionUtils.isEmpty(jadeBOList)) {
            return new ArrayList<>(0);
        }
        List<String> inboundOrderIdList = jadeBOList.stream()
                .map(WmsJadeBO::getOrderCode)
                .distinct()
                .collect(Collectors.toList());
        Map<String, String> orderTypeMap = wmsInboundOrderRepository.findByOrderCodeList(inboundOrderIdList, query.getTenantId(), false)
                .stream()
                .collect(Collectors.toMap(WmsInboundOrderBO::getOrderCode, WmsInboundOrderBO::getOrderType));
        List<WmsWarehouseBO> warehouseBOList = wmsWarehouseRepository.findByIds(jadeBOList.stream().map(WmsJadeBO::getWarehouseId).distinct().collect(Collectors.toList()), query.getTenantId());
        Map<Long, WmsWarehouseBO> warehouseBOMap = warehouseBOList.stream().collect(Collectors.toMap(WmsWarehouseBO::getId, Function.identity()));
        Map<Long, WmsWarehouseStorageBO> warehouseStorageBOMap = warehouseBOList.stream()
                .map(WmsWarehouseBO::getStorageMap)
                .flatMap(map -> map.values().stream())
                .collect(Collectors.toMap(WmsWarehouseStorageBO::getId, Function.identity()));

        // 组装VO数据
        return wmsInboundVOAssembler.toInboundJadeVOList(jadeBOList, orderTypeMap, warehouseBOMap, warehouseStorageBOMap);
    }

    /**
     * 执行入库操作
     * @param inboundDTO 入库数据
     */
    @Transactional
    public AjaxResult add(InboundDTO inboundDTO){
        Long tenantId = SecurityUtils.getLoginUser().getTenantId();

        // 防重入
        String preKey = INBOUND_PREFIX+tenantId+":"+inboundDTO.getOrderCode();
        Long num = stringRedisTemplate.opsForValue().increment(preKey, 1L);
        log.info("入库操作：Redis计数器: {}",num);
        //已经有一个对应单号的入库单在创建
        if(!num.equals(1L)){
            throw new ServiceException("入库单重复提交");
        }
        stringRedisTemplate.expire(preKey,5, TimeUnit.SECONDS);

        String dupPrefix = INBOUND_PREFIX + DUP_KEY + tenantId + ":" + inboundDTO.getOrderCode();
        //查询缓存是否存在限制
        if (stringRedisTemplate.opsForValue().get(dupPrefix)!=null) {
            //存在则重新设置过期时间
            stringRedisTemplate.expire(dupPrefix,1+new Random().nextLong(), TimeUnit.SECONDS);
            throw new ServiceException("入库单重复提交");
        }
        //检查数据库中是否存在对应数据，存在则设置缓存
        if(wmsInboundOrderMapper.selectOne(new QueryWrapper<WmsInboundOrderPO>().eq("order_code",inboundDTO.getOrderCode()).eq("tenant_id",tenantId))!=null){
            //执行lua脚本设置缓存
            stringRedisTemplate.execute(RedisConstants.DUPLICATE_SCRIPT,new ArrayList<>(), dupPrefix,"",1000L+new Random().nextInt(1000));
            throw new ServiceException("入库单重复提交");
        }

        // TODO：2024/1/22 11:14 参数校验（部分已由注解完成）
        List<InboundDTO.InboundDetailDTO> inboundList = inboundDTO.getInboundDetailDTOList();
        if(inboundList==null) return AjaxResult.error(SystemConstants.JADE_EMPTY);
        // 获取仓库信息
        WmsWarehouseDO wmsWarehouseDO = wmsWarehouseRepository.findById(inboundDTO.getDesWarehouseId(), tenantId);
        if (wmsWarehouseDO == null) {
            return AjaxResult.error(SystemConstants.WAREHOUSE_NOT_EXIST);
        }
        // 检查是否允许入库
        String status = wmsWarehouseDO.getStatus();
        if(status.equals("2") || status.equals("3")) return AjaxResult.error(SystemConstants.INBOARD_REFUSED);
        // 检查 仓位 容量
        int total = 0;

        //计算总量
        for (InboundDTO.InboundDetailDTO one : inboundList) {
            total+=one.getJadeQuantity();
        }
        //仓库大小指的是指仓库旗下所有仓位容量之和，不检查
//        //超出 仓库 容量
//        if (wmsWarehouseDO.getMaxCap()!=-1&&
//                wmsWarehouseDO.getUsedCap()+total>wmsWarehouseDO.getMaxCap())
//            return AjaxResult.error(SystemConstants.WAREHOUSE_NO_SPACE);

        WmsWarehouseStoragePO storage = wmsWarehouseRepository.findStorageById(inboundDTO.getDesStorageId(), tenantId);
        //超出 仓位 容量
        if (storage.getMaxCap()!=-1&&
                storage.getUsedCap()+total>storage.getMaxCap())
            return AjaxResult.error(SystemConstants.WAREHOUSE_STORAGE_NO_SPACE);

        //判断是否需要审核
        boolean needAudit = total>500;

        // 创建入库单
        WmsInboundOrderPO inboundOrder = createInboundOrder(inboundDTO);



        //是采借入库
        if (StringUtils.equals(inboundDTO.getOrderType(), InboundConstants.INBOUND_ORDER_TYPE_BUY) ||
                        StringUtils.equals(inboundDTO.getOrderType(), InboundConstants.INBOUND_ORDER_TYPE_BORROW)
        ) {
            // 判断是否需要审核
            if(needAudit) {
                Long auditId = idGenerator.nextId("audit");
                // 创建审核单
                if(auditOrderService.create("3", auditId)==null) return AjaxResult.error("创建审核单失败");
                inboundOrder.setAuditId(auditId);
            }

            //主单入库
            wmsInboundOrderMapper.insert(inboundOrder);

            // 处理采借入库
            for (InboundDTO.InboundDetailDTO inboundDetailDTO : inboundDTO.getInboundDetailDTOList()) {
                // 创建jade数据
                WmsJadePO wmsJadePO = createJade(inboundDTO, inboundDetailDTO);

                //需要审核，设置为不可见
                if (needAudit) wmsJadePO.setDelFlag(JadeConstants.JADE_INVISIBLE);
                wmsJadeMapper.insert(wmsJadePO);

                // 创建入库明细
                createInboundOrderDetail(inboundDTO, inboundDetailDTO, wmsJadePO);
            }
        }
        //是还货入库
        else if (StringUtils.equals(inboundDTO.getOrderType(), InboundConstants.INBOUND_ORDER_TYPE_RETURN) ||
                StringUtils.equals(inboundDTO.getOrderType(), InboundConstants.INBOUND_ORDER_TYPE_PROCESS) ||
                StringUtils.equals(inboundDTO.getOrderType(), InboundConstants.INBOUND_ORDER_TYPE_BACK)
        ){
            //判断选择的入库类型是否正确
            String outboundType=wmsOutboundOrderMapper.getOutboundType(inboundDTO.getOutboundOrderCode());
            if (inboundDTO.getOrderType().equals(InboundConstants.INBOUND_ORDER_TYPE_RETURN)&&!outboundType.equals(OutboundType.BORROW)){
                throw new ServiceException("只有借货出库的货品可以进行还货入库");
            }else if (inboundDTO.getOrderType().equals(InboundConstants.INBOUND_ORDER_TYPE_BACK)&&!outboundType.equals(OutboundType.BORROW)){
                throw new ServiceException("只有销售出库的货品可以进行退货入库");
            }
            // 判断是否需要审核
            if(needAudit) {
                // 创建审核单
                Long auditId = auditOrderService.create("3", inboundOrder.getId());
                if(auditId==null) return AjaxResult.error("创建审核单失败");
                inboundOrder.setAuditId(auditId);
            }

            //主单入库
            wmsInboundOrderMapper.insert(inboundOrder);

            // 还货入库
            for (InboundDTO.InboundDetailDTO inboundDetailDTO : inboundDTO.getInboundDetailDTOList()) {
                // 不需要审核，直接（仅）更新jade状态
                if (!needAudit) {
                    jadeService.updateJadeStatus(JadeConstants.JADE_IN_WAREHOUSE, inboundDetailDTO.getJadeId());
                }

                // 获取jade（创建详情单不需要用到jade状态，因此互不影响）
                WmsJadePO wmsJadePO = wmsJadeMapper.selectById(inboundDetailDTO.getJadeId());
                createInboundOrderDetail(inboundDTO, inboundDetailDTO, wmsJadePO);
            }
        }
        return AjaxResult.success();
    }

    /**
     * 创建入库单
     * @param inboundDTO 入库单DTO
     * @return 入库单PO
     */
    private WmsInboundOrderPO createInboundOrder(InboundDTO inboundDTO) {
        // 创建入库单
        WmsInboundOrderPO wmsInboundOrderPO = new WmsInboundOrderPO();
        BeanUtils.copyProperties(inboundDTO, wmsInboundOrderPO);

        wmsInboundOrderPO.setId(idGenerator.nextId("inbound"));
        wmsInboundOrderPO.setTenantId(SecurityUtils.getLoginUser().getTenantId());
        wmsInboundOrderPO.setDeptId(DeptConstants.DEPT_ID_DEFAULT);
        wmsInboundOrderPO.setCreateBy(SecurityUtils.getLoginUser().getUsername());
        wmsInboundOrderPO.setUpdateBy(SecurityUtils.getLoginUser().getUsername());
        wmsInboundOrderPO.setDelFlag("0");

        return wmsInboundOrderPO;
    }

    private WmsJadePO createJade(InboundDTO inboundDTO, InboundDTO.InboundDetailDTO inboundDetailDTO) {
        WmsJadePO wmsJadePO = new WmsJadePO();
        BeanUtils.copyProperties(inboundDTO, wmsJadePO);
        BeanUtils.copyProperties(inboundDetailDTO, wmsJadePO);

        wmsJadePO.setJadeCode(jadeService.getNewCode(SecurityUtils.getLoginUser().getUser()));
        wmsJadePO.setWarehouseId(inboundDTO.getDesWarehouseId());
        wmsJadePO.setStorageId(inboundDTO.getDesStorageId());

        String jadeTypeIds = inboundDetailDTO.getJadeTypeId();
        if (StringUtils.isNotBlank(jadeTypeIds)) {
            String[] jadeTypeIdArray = jadeTypeIds.split("-");
            int size = jadeTypeIdArray.length;
            Long jadeTypeId = null;
            Long jadeNameId = null;
            switch (size) {
                case 1:
                    jadeTypeId = Long.valueOf(jadeTypeIdArray[0]);
                    jadeNameId = Long.valueOf(jadeTypeIdArray[0]);
                    break;
                case 2:
                    jadeTypeId = Long.valueOf(jadeTypeIdArray[1]);
                    jadeNameId = Long.valueOf(jadeTypeIdArray[0]);
                    break;
                default:
                    log.warn("当前最多支持两级jadeTypeId参数，当前参数为：{}", jadeTypeIds);
                    break;
            }
            wmsJadePO.setJadeTypeId(jadeTypeId);
            WmsJadeTypeBO wmsJadeTypeBO = wmsJadeRepository.getJadeTypeBOMap().get(jadeNameId);
            wmsJadePO.setJadeName(Optional.ofNullable(wmsJadeTypeBO.getJadeTypeName()).orElse("未知翡翠名称"));
        }

        wmsJadePO.setTenantId(SecurityUtils.getLoginUser().getTenantId());
        wmsJadePO.setDeptId(DeptConstants.DEPT_ID_DEFAULT);
        wmsJadePO.setCreateBy(SecurityUtils.getLoginUser().getUsername());
        wmsJadePO.setUpdateBy(SecurityUtils.getLoginUser().getUsername());
        wmsJadePO.setDelFlag("0");

        wmsJadePO.setStatus(JadeConstants.JADE_IN_WAREHOUSE);

        return wmsJadePO;
    }

    private void createInboundOrderDetail(
            InboundDTO inboundDTO,
            InboundDTO.InboundDetailDTO inboundDetailDTO,
            WmsJadePO wmsJadePO
    ) {
        // 创建入库单明细
        WmsInboundOrderDetailPO wmsInboundOrderDetailPO = new WmsInboundOrderDetailPO();
        BeanUtils.copyProperties(inboundDetailDTO, wmsInboundOrderDetailPO);
        BeanUtils.copyProperties(wmsJadePO, wmsInboundOrderDetailPO);
        wmsInboundOrderDetailPO.setInboundOrderCode(inboundDTO.getOrderCode());
        wmsInboundOrderDetailPO.setDesStorageId(inboundDTO.getDesStorageId());
        wmsInboundOrderDetailPO.setJadeId(wmsJadePO.getId());
        wmsInboundOrderDetailPO.setDelFlag("0");
        wmsInboundOrderDetailMapper.insert(wmsInboundOrderDetailPO);
    }

    public void merge(List<Long> inboundOrderIds) {
        if (CollectionUtils.isEmpty(inboundOrderIds)) {
            log.error("入库单id为空");
            throw new ServiceException("入库单id为空");
        }
        List<WmsInboundOrderPO> wmsInboundOrderPOS = wmsInboundOrderMapper.selectList(
                new LambdaQueryWrapper<WmsInboundOrderPO>()
                        .in(WmsInboundOrderPO::getId, inboundOrderIds)
        );

        // 检查是否满足合并要求
        if (CollectionUtils.isEmpty(wmsInboundOrderPOS)) {
            throw new ServiceException("采购单为空");
        }
//        boolean match = wmsInboundOrderPOS.stream()
//                .allMatch(item -> StringUtils.equals(item.getOrderType(), InboundConstants.INBOUND_ORDER_TYPE_BUY));
        boolean match = true;
        for (WmsInboundOrderPO item : wmsInboundOrderPOS) {
            //判断到不是采借入库
            if(!item.getOrderType().equals(InboundConstants.INBOUND_ORDER_TYPE_BUY) &&
                    !item.getOrderType().equals(InboundConstants.INBOUND_ORDER_TYPE_BORROW)){
                match = false;
                break;
            }
        }
        if (!match) {
            throw new ServiceException("仅支持合并采借入库单");
        }
        Set<Long> supplierSet = wmsInboundOrderPOS.stream()
                .map(WmsInboundOrderPO::getSupplierId)
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(supplierSet) || supplierSet.size() != 1) {
            throw new ServiceException("仅支持合并同一个供应商的采购入库单");
        }

        // 拿到第一条的数据，去第一条的入库单数据为准
        WmsInboundOrderPO one = Objects.requireNonNull(CollectionUtils.firstElement(wmsInboundOrderPOS));

        // 创建入库单
        WmsInboundOrderPO wmsInboundOrderPO = new WmsInboundOrderPO();
        wmsInboundOrderPO.setOrderType(InboundConstants.INBOUND_ORDER_TYPE_BUY);
        String newOrderCode = getNewCode(SecurityUtils.getLoginUser().getUser());
        wmsInboundOrderPO.setOrderCode(newOrderCode);
        wmsInboundOrderPO.setSupplierId(one.getSupplierId());
        wmsInboundOrderPO.setDesWarehouseId(one.getDesWarehouseId());

        wmsInboundOrderPO.setTenantId(SecurityUtils.getLoginUser().getTenantId());
        wmsInboundOrderPO.setCreateTime(DateUtils.getNowDate());
        wmsInboundOrderPO.setDeptId(DeptConstants.DEPT_ID_DEFAULT);
        wmsInboundOrderPO.setCreateTime(new Date());
        wmsInboundOrderPO.setCreateBy(SecurityUtils.getLoginUser().getUsername());
        wmsInboundOrderPO.setUpdateTime(new Date());
        wmsInboundOrderPO.setUpdateBy(SecurityUtils.getLoginUser().getUsername());
        wmsInboundOrderPO.setDelFlag("0");
        wmsInboundOrderMapper.insert(wmsInboundOrderPO);


        // 将原有入库单明细指向新的入库单
        // TODO: 保险一点的做法应该是将旧的明细删除，复制一份新的明细关联新的入库单
        wmsInboundOrderDetailMapper.update(
                null,
                new LambdaUpdateWrapper<WmsInboundOrderDetailPO>()
                        .in(
                                WmsInboundOrderDetailPO::getInboundOrderCode,
                                wmsInboundOrderPOS.stream()
                                        .map(WmsInboundOrderPO::getOrderCode)
                                        .collect(Collectors.toList())
                        )
                        .set(WmsInboundOrderDetailPO::getInboundOrderCode, newOrderCode)

        );

        // 删除旧的入库单
        wmsInboundOrderMapper.update(
                null,
                new LambdaUpdateWrapper<WmsInboundOrderPO>()
                        .in(
                                WmsInboundOrderPO::getId,
                                wmsInboundOrderPOS.stream()
                                        .map(WmsInboundOrderPO::getId)
                                        .collect(Collectors.toList())
                        )
                        .set(WmsInboundOrderPO::getDelFlag, "2")
        );
    }

    public String getNewCode(SysUser user) {
        // 获取数据库中最大的编码
        String maxCode = getMaxCode(user);
        String userCode = user.getUserCode();

        // 返回maxCode为NULL，及当前数据库没有数据，从0开始
        if (com.scau402.common.utils.StringUtils.isNull(maxCode)) {
            maxCode = InboundConstants.MAX_CODE_ZERO;
        }

        // 获取当前用户所属租户编码
        Long loginUserTenantId = SecurityUtils.getLoginUser().getTenantId();
        String loginUserTenantCode = tenantService.selectSysTenantByTenantId(loginUserTenantId).getTenantCode();

        // 设置redis的当前编码
        InboundOrderCodeUtils inboundOrderCodeUtils = new InboundOrderCodeUtils();
        inboundOrderCodeUtils.setCurrentCodeToMax(maxCode, loginUserTenantCode, userCode);
        return InboundOrderCodeUtils.getNewCode(loginUserTenantCode, userCode);
    }

    public String getMaxCode(SysUser user) {
        Long tenantId = user.getTenantId();
        String userCode = user.getUserCode();
        userCode = userCode.substring(1);
        Map<String, Object> params = new HashMap<>();
        // 设置参数值
        params.put("tenantId", tenantId);
        params.put("userCode", userCode);
        return wmsInboundOrderMapper.getMaxCode(params);
    }

    public boolean checkExists(String inboundOrderCode) {
        return wmsInboundOrderMapper.checkExists(inboundOrderCode) > 0;
    }

    @Override
    public WmsInboundOrderPO getByInboundOrderCode(String inboundOrderCode) {
        return wmsInboundOrderMapper.getByInboundOrderCode(inboundOrderCode);
    }

    @Override
    public Map<Long, String> getInboundTypeList(List<Long> wmsJadeIdList, Long type) {
        if (CollectionUtils.isEmpty(wmsJadeIdList)) {
            return new HashMap<>(0);
        }
        Map<Long, String> jadeIdInboundOrderCodeMap = Optional
                .ofNullable(wmsInboundOrderDetailMapper.selectList(Wrappers.<WmsInboundOrderDetailPO>lambdaQuery()
                        .eq(WmsInboundOrderDetailPO::getDelFlag, "0")
                        .in(WmsInboundOrderDetailPO::getJadeId, wmsJadeIdList)
                ))
                .orElse(new ArrayList<>(0))
                .stream()
                .collect(Collectors.toMap(WmsInboundOrderDetailPO::getJadeId, WmsInboundOrderDetailPO::getInboundOrderCode));
        if (CollectionUtils.isEmpty(jadeIdInboundOrderCodeMap)) {
            log.warn("根据玉石ID列表获取入库单编码map为空，玉石ID列表：{}", wmsJadeIdList);
            return new HashMap<>(0);
        }
        List<String> inboundOrderCodeList = jadeIdInboundOrderCodeMap.values().stream()
                .distinct()
                .collect(Collectors.toList());
        List<WmsInboundOrderPO> wmsInboundOrderPOList = null;
        if (null != type) {
            wmsInboundOrderPOList = Optional
                    .ofNullable(wmsInboundOrderMapper.selectList(Wrappers.<WmsInboundOrderPO>lambdaQuery()
                            //检测类型
                            .eq(  WmsInboundOrderPO::getOrderType, type.toString())
                            .eq(WmsInboundOrderPO::getDelFlag, "0")
                            .in(WmsInboundOrderPO::getOrderCode, inboundOrderCodeList)
                    ))
                    .orElse(new ArrayList<>(0));
        } else {
            wmsInboundOrderPOList = Optional
                    .ofNullable(wmsInboundOrderMapper.selectList(Wrappers.<WmsInboundOrderPO>lambdaQuery()
                            //检测类型
                            .eq(WmsInboundOrderPO::getDelFlag, "0")
                            .in(WmsInboundOrderPO::getOrderCode, inboundOrderCodeList)
                    ))
                    .orElse(new ArrayList<>(0));
        }

        if (CollectionUtils.isEmpty(wmsInboundOrderPOList)) {
            log.warn("根据入库单编码列表获取入库单列表为空，入库单编码列表：{}", inboundOrderCodeList);
            return new HashMap<>(0);
        }
        Map<String, String> inboundTypeMap = wmsInboundOrderPOList.stream()
                .peek(po -> {
                    switch (po.getOrderType()) {
                        case InboundConstants.INBOUND_ORDER_TYPE_BUY:
                            po.setOrderType("采购入库");
                            break;
                        case InboundConstants.INBOUND_ORDER_TYPE_BORROW:
                            po.setOrderType("借货入库");
                            break;
                        case InboundConstants.INBOUND_ORDER_TYPE_RETURN:
                            po.setOrderType("还货入库");
                            break;
                        case InboundConstants.INBOUND_ORDER_TYPE_PROCESS:
                            po.setOrderType("加工入库");
                            break;
                        default:
                            po.setOrderType("未知类型");
                            break;
                    }
                })
                .collect(Collectors.toMap(WmsInboundOrderPO::getOrderCode, WmsInboundOrderPO::getOrderType));
        //包装
        jadeIdInboundOrderCodeMap.entrySet().removeIf(entry -> !inboundTypeMap.containsKey(entry.getValue()));
        jadeIdInboundOrderCodeMap.entrySet().forEach(entry -> {
            String newValue = inboundTypeMap.get(entry.getValue());
            if (newValue != null) {
                entry.setValue(newValue);
            }
        });
        return jadeIdInboundOrderCodeMap;
//        return jadeIdInboundOrderCodeMap.entrySet().stream()
//                .collect(Collectors.toMap(Map.Entry::getKey, entry -> inboundTypeMap.get(entry.getValue())));
    }

    @Override
    public AjaxResult deleteWmsInboundOrderByIds(Long[] ids) {
        for (Long id:ids) {
            WmsInboundOrderPO wmsInboundOrder = wmsInboundOrderMapper.selectById(id);
            String orderType = wmsInboundOrder.getOrderType();
            if (orderType.equals("2")||orderType.equals("3")){
                throw new ServiceException("只可删除采借入库的入库单");
            }else {
                WmsInboundOrderPO delete=new WmsInboundOrderPO();
                delete.setId(id);
                delete.setDelFlag("2");
                wmsInboundOrderMapper.updateById(delete);
            }
        }
        return AjaxResult.success();
    }
}